package cc.verywell.pureblock.msg.nfs.idx.extraUpload;

import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;

import cc.verywell.pureblock.func.node.KeyShell;
import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.msg.nfs.idx.NfsidxStructure;
import cc.verywell.pureblock.util.StringUtil;

/**
* 
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年10月2日 下午9:26:44
*/
public class UploadingMonitor implements Closeable{

	final public byte[] absolutePath;
	public ArrayList<UploadingWatch> watchs;
	public HashSet<UploadingWatch> set;
	public UploadManager manager;
	private final boolean closeWhenFinish;
	private boolean closed = false;
	/**
	 * 因为要取得UploadManager，原则上在UploadManager内获取即可;
	 * @param manager
	 * @param absolutePath
	 * @param closeWhenFinish是否上传网络后自动关闭
	 */
	UploadingMonitor(UploadManager manager,byte[] absolutePath,boolean closeWhenFinish) {
		watchs = new ArrayList<UploadingWatch>();
		set = new HashSet<UploadingWatch>();
		this.manager = manager;
		this.absolutePath = absolutePath;
		this.closeWhenFinish = closeWhenFinish;
	}
	void addbyWatch(UploadingWatch watch) { //由watch调用
		watchs.add(watch);
		if(!isFinished(watch)) {
			synchronized (set) {
				set.add(watch);
			}
		}
	}
	
	public void fireStateUpdate(UploadingWatch watch) {
		boolean allFinished = false;
		if(isFinished(watch)) {
			synchronized (set) {
				set.remove(watch);
				allFinished = set.isEmpty();
			}
		}
		if(allFinished) {
			//完成后应该怎么做，是继续做种还是马上撤回?
			if(closeWhenFinish)close();
		}
	}
	void fireUploadReadybyManager() {
		boolean allFinished = false;
			synchronized (set) {
				allFinished = set.isEmpty();
			}
		if(allFinished) {
			//完成后应该怎么做，是继续做种还是马上撤回?
			if(closeWhenFinish) {
				close();
				manager.removeMonitorbyUploadingMonitor(this);///有可能在完成后立即处理完毕
			}
		}
	}
	
	protected boolean isFinished(UploadingWatch watch) {
		return (watch.storeCount>2);
	}
	
	//文件错误，终止上传
	public void fireNoMoreIdx(KeyShell key,NfsidxStructure idx) {
		//TODO 增加终止上传记录;
		close();
	}
	
	@Override
	public void close(){
		synchronized (watchs) {
			if(closed)return;//已经处理过了;
			closed = true;
			boolean needUnhold = false;
			for (UploadingWatch w : watchs) {
				synchronized (w) {
					NfsidxStructure oldidx = w.removeMonitorByMonitor(this);
					if(oldidx!=null) {
						if(oldidx.isExternal()) {
							NfsidxStructure newidx = w.needNewExternalFile(w.key, null);
							if(newidx!=null) {
								if(!newidx.equals(oldidx))
									manager.out.replaceIndex(w.key, oldidx, newidx);
							}else {
								manager.out.removeIndex(w.key, oldidx);
							}
						}else {
							needUnhold = true;
						}
						manager.removeWatchbyUploadingMonitor(w);
					}
				}
			}
			watchs.clear();
			if(needUnhold)manager.out.removeHold(this);
			manager.removeMonitorbyUploadingMonitor(this);
		}
	}
	
	
	////20200204 为DownloadManager提供上传支持
	public void newDataReady(KeyShell key, long totalsize, long pos, long len) {
		if(closed)return;
		manager.newDataReadyByUploadingMonitor(key, this, absolutePath, totalsize, pos, len);
	}
	public void tryHoldInternal(KeyShell key,byte[] payload) {
		if(closed)return;
		manager.tryHoldInternal(this,key,payload);
	}
	
	
	////数据保存
	public KeyShell mainKey;
	@Override
	public String toString() {
		int total,rest;
		synchronized (watchs) {total = watchs.size();}
		synchronized (set) {rest = set.size();}
		return StringUtil.byteToString(absolutePath)+" ["+(mainKey==null?"":Pblog.byteArray2Hex(mainKey.key))+"]: "+(total-rest)+"(uploaded)/"+total+"(total pack)";
	}

	

}
